
# A Getter is the abstract parent class for a tree of objects that respond to the method 'get'.
# The concrete classes are responsible for providing a 'getter', a first class function
# that returns a value of any type when called. 'get' will call this function,
# then this value will be added to a 'history' hash, keyed on the time of calling.
# There are locks for thread safety, so many threads can use one getter(saves bandwidth).
# - All the subclasses need to do is instantiate the '@getter' object, an anonymous function that returns a string.
class Getter
	require 'thread'
	attr_reader :history, :last_updated
	def initialize
		@history = {} 
		
		#since multiple updaters could be using this getter, we're gunna need some thread saftey
		@get_lock = Mutex.new 
	end
	def get
		@get_lock.synchronize {
			value = @getter.call
			#only add this value to history if there isnt one already for this second.
			@history[Time.now] = value if !@history.include?(Time.now)
			@last_updated = Time.now
			return value
		}
	end
end

#array getters and text getters should be different subtypes because of LSP - their 'get' returns data of differnt types.
# its not really nessecary, because ruby is dynamically typed, but whatever.
class ArrayGetter < Getter 
end
class TextGetter < Getter 
	def get
	  #call super.get, then force the result to a string. Not strictly nessecary,
	  #but ruby will not allow '+' concatenation of strings and ints, so its nice.
		return super.to_s
	end
end

#WeatherGetter is a mixin module that provides the data sources for all that include it.
module WeatherGetter
	require 'soap/wsdlDriver'

	#WSDL_URL = "http://viper.infotech.monash.edu.au/~davids/FIT3077/MelbourneWeather2.wsdl"
	WSDL_URL = "http://viper.infotech.monash.edu.au/~davids/FIT3077/MelbourneWeatherTimeLapse.wsdl"
	WeatherService = SOAP::WSDLDriverFactory.new(WSDL_URL).create_rpc_driver
end

#The group of concrete 'getter' classes.
#Each one simply ininializes a first-class function that when called returns information from the weather service.
#They all mixin the 'WeatherGetter' module to provide the weatherservice constants.
class LocationsGetter < ArrayGetter
	include WeatherGetter
	def initialize
		super
		@getter = lambda { WeatherService.getLocations[0] }
	end
end

class TempGetter < TextGetter
	include WeatherGetter
	
	#'new' method requires a location that we're getting the temp of
	def initialize(location) 
		super()
		@location = location
		@getter = lambda { WeatherService.getTemperature(@location)[0].to_f}
	end
end

class RainfallGetter < TextGetter
	include WeatherGetter
	
	#'new' method requires a location that we're getting the temp of
	def initialize(location) 
	  super()
		@location = location
		@getter = lambda {WeatherService.getRainfall(@location)[0].to_f; rand 4}
	end
end
